'''
= Constraint Checking =

This module provides the check-function to check function or method pre-
conditions. It is used as a decorator:

    def can_foo(bar, baz):
        return bar < baz
    
    @check(can_foo)
    def foo(bar, baz):
        return baz - bar
    
    @check(lambda quuux: quuux.startswith('q'),
          on_failure_return = 'Q!')
    def quux(quuux):
        return quuux + '!'
'''

from functools import wraps


def check(precondition, on_failure_return = None):
    '''Decorator that takes a function and an optional failure return value
    as arguments.
    
    The function argument is called prior to the decorated function, with the
    same arguments. If that function returns true, the decorated function is
    executed as normal and its return value is passed through. Otherwise, the
    failure return value is returned.'''
    
    def decorator(f):
        @wraps(f)
        def g(*args, **kwds):
            if not precondition(*args, **kwds):
                return on_failure_return
            else:
                return f(*args, **kwds)
        
        return g
    
    return decorator
